/*
 * Copyright (C) 2011 flashflexpro@gmail.com  All Rights Reserved.  No
 *   use, copying or distribution of this work may be made except in
 *   accordance with a valid license agreement from flashflexpro@gmail.com
 *   This notice must be included on all copies, modifications and
 *   derivatives of this work.
 *
 *   flashflexpro@gmail.com MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT
 *   THE SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
 *   INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 *   NON-INFRINGEMENT. flashflexpro@gmail.com SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED
 *   BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS
 *   SOFTWARE OR ITS DERIVATIVES.
 */

package com.flashflexpro.as3lib{
    import flash.display.DisplayObject;
    import flash.events.Event;
    import flash.utils.Dictionary;

    public class CallOnceInNextFrame{


        public function putIn( func:Function, args:Array = null, thisObj:Object = null, skipFrameNum:int = 1 ):Boolean{
            if( _dic[ func ] != null ){
                return false;
            }
            _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
            _displayObject.addEventListener( Event.ENTER_FRAME, onEnterFrame );
            _dic[ func ] = [ args, thisObj, skipFrameNum ];
            return true;
        }

        public function getOut( func:Function ):Array{
            return _dic[ func ] as Array;
        }

        public function cancel( func:Function ):void{
            delete _dic[ func ];
        }
        public function cancelAll():void{
            _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
            _dic = new Dictionary();
            /*
            for( var func:Object in _dic ){
                delete _dic[ func ];
            }*/
        }

        public function destroy():void{
            _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
            _displayObject = null;
        }


        public function replace( func:Function, args:Array = null, thisObj:Object = null ):Boolean{
            var exist:Boolean = false;
            if( _dic[ func ] != null ){
                exist = true;
            }
            _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
            _displayObject.addEventListener( Event.ENTER_FRAME, onEnterFrame );
            _dic[ func ] = [ args, thisObj ];
            return exist;
        }


        private var _dic:Dictionary = new Dictionary( );

        private var _displayObject:DisplayObject;


        public function get displayObject():DisplayObject{
            return _displayObject;
        }

        public function set displayObject( value:DisplayObject ):void{
            if( value != null && _displayObject != value ){
                if( _displayObject != null ){
                    _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
                }
                _displayObject = value;
            }
        }

        private function onEnterFrame( event:Event ):void{
            var notEmpty:Boolean = false;
            var toDel:Array = [];
            for( var f:* in _dic ){
                notEmpty = true;
                var argsThisAndSkipNum:Array = _dic[ f ];
                argsThisAndSkipNum[ 2 ] --;
                if( argsThisAndSkipNum[ 2 ] <= 0 ){
                    toDel.push( f );

                    var func:Function = f as Function;
                    func.apply( argsThisAndSkipNum[ 1 ], argsThisAndSkipNum[ 0 ] );
                }
            }
            for( var i:int = toDel.length - 1; i >= 0; i-- ){
                delete _dic[ toDel[i] ];
            }
            if( !notEmpty ){
                _displayObject.removeEventListener( Event.ENTER_FRAME, onEnterFrame );
            }
        }
    }
}